package com.xms.configuration.service;

import com.xms.configuration.entity.Settings;
import com.xms.configuration.event.SettingUpdatedEvent;
import com.xms.utils.CollectionUtil;
import com.xms.utils.RefletUtil;
import com.xms.utils.StringUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Service;

import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;

/**
 * <p>
 * SettingFinder
 * </p>
 *
 * @author migo
 * @since 2021/9/26
 */
@Service
public class SettingFactory implements ISettingFactory {
    private ISettingFinderService _settingFinderService;
    private ConcurrentHashMap<String, Object> _instances = new ConcurrentHashMap<>();

    @Autowired
    public void SettingFinder(ISettingFinderService settingFinderService) {
        _settingFinderService = settingFinderService;
    }

    @Override
    public <T> T getObject(Class<T> clazz) throws InstantiationException, IllegalAccessException, NoSuchFieldException {
        return this.getObject(clazz, null);
    }

    @Override
    public <T> T getObject(Class<T> clazz, String nameSpace) throws InstantiationException, IllegalAccessException, NoSuchFieldException {
        nameSpace = StringUtil.isEmpty(nameSpace) ? clazz.getName() : nameSpace;
        if(_instances.containsKey(nameSpace)){
            return (T)_instances.get(nameSpace);
        }
        List<Settings> list = _settingFinderService.getByNamespace(nameSpace);
        if (CollectionUtil.isEmpty(list))
            return null;
        T entity = clazz.newInstance();
        List<Field> fields = Arrays.asList(clazz.getFields());
        for (Settings s : list) {
            String realName = s.getName().substring(s.getName().lastIndexOf(".") + 1);
            Field field = fields.stream().filter(x -> x.getName().equalsIgnoreCase(realName)).findFirst().orElse(null);
            if (field != null) {
                RefletUtil.setFieldValue(entity, field, s.getValue());
            }
        }
        _instances.put(nameSpace, entity);
        return entity;
    }

    @Override
    public HashMap<String, String> getKeyValues(String nameSpace) {
        List<Settings> list = _settingFinderService.getByNamespace(nameSpace);
        if (CollectionUtil.isEmpty(list))
            return null;
        HashMap<String, String> result = new HashMap<>();
        for (Settings s : list) {
            result.put(s.getName(), s.getValue());
        }
        return result;
    }

    @EventListener
    public void settingChanged(SettingUpdatedEvent eventMessage){
        this._instances.remove(eventMessage.getSource());
    }
}
